/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.mekegi.whoanthro.Sql;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.CursorIndexOutOfBoundsException;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.mekegi.whoanthro.AbstractModel;
import com.mekegi.whoanthro.Child;
import com.mekegi.whoanthro.IModel;

/**
 * @since 24.02.13 23:13
 * @author Arsen Abdusalamov <duburlan@gmail.com>
 */
abstract public class AbstractSqlAdapter extends BaseAdapter {

    protected static final String DB_NAME = "anthro.sqlite3";
    protected static final String KEY_DB_VERSION = "key_db";
    protected static final String KEY_TABLE_NAME = "key_table_name";
    protected static final String KEY_LAYOUT_ID = "key_layout_id";
    protected static final String KEY_MODEL_FOR_FACTORY = "key_model_for_factory";

    abstract protected ContentValues getConfigMap();

    abstract protected String getCreateTableSql();

    abstract protected String[] getColumnsToTake();

    protected int getDbVersion() {
        ContentValues conf = getConfigMap();
        return conf.getAsInteger(KEY_DB_VERSION);
    }

    protected String getTableName() {
        ContentValues conf = getConfigMap();
        return conf.getAsString(KEY_TABLE_NAME);
    }

    protected int getModelKeyForFactory() {
        ContentValues conf = getConfigMap();
        return conf.getAsInteger(KEY_MODEL_FOR_FACTORY);
    }

    protected int getLayoutId() {
        ContentValues conf = getConfigMap();
        return conf.getAsInteger(KEY_LAYOUT_ID);
    }
    protected static final String KEY_ID = "_id";
    protected Cursor cursor;
    protected SQLiteDatabase database;
    protected DbOpenHelper dbOpenHelper;
    protected Context context;

    //Далее следуют обязательные к перегрузке методы адаптера
    public AbstractSqlAdapter(Context context) {
        super();
        this.context = context;
        init();
    }

    @Override
    public long getItemId(int position) {
        IModel modelOnPosition = getItem(position);
        return modelOnPosition.getId();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parrent) {
        TextView textView;
        if (null == convertView) {
            textView = (TextView) View.inflate(context, getLayoutId(), null);
        } else {
            textView = (TextView) convertView;
        }
        textView.setText(getItem(position).getTextForView());
        return textView;
    }

    @Override
    public int getCount() {
        return cursor.getCount();
    }

    @Override
    public IModel getItem(int position) {
        if (cursor.moveToPosition(position)) {
            return cursorToModel(cursor);
        } else {
            throw new CursorIndexOutOfBoundsException(
                    "Cant move cursor to postion");
        }
    }

    //Методы для работы с базой данных
    public Cursor getAllEntries() {
        return database.query(getTableName(), getColumnsToTake(),
                null, null, null, null, KEY_ID);
    }

    public long addItem(IModel model) {
        ContentValues values = model.toContentValues();
        long id = database.insert(getTableName(), null, values);
        model.setId(id);
        refresh();
        return id;
    }

    public boolean removeItem(IModel modelToRemove) {
        boolean isDeleted = (database.delete(getTableName(), KEY_ID + "=?",
                new String[]{modelToRemove.getId().toString()})) > 0;
        refresh();
        return isDeleted;
    }

    /**
     * return model by primary key
     *
     * @since 26.02.13 14:12
     * @param id
     * @return
     */
    public IModel findItemByPK(int id) {
        Cursor anotherCursor = database.query(getTableName(), getColumnsToTake(),
                KEY_ID + "=?", new String[]{id + ""}, null, null, null, "1");
        anotherCursor.moveToFirst();
        return cursorToModel(anotherCursor);
    }

    /**
     * return model by primary key
     *
     * @since 26.02.13 14:12
     * @param id
     * @return
     */
    public IModel findItemByPK(Long id) {
        return findItemByPK(id.intValue());
    }

    protected IModel cursorToModel(Cursor anotherCursor) {
        IModel model = AbstractModel.factory(getModelKeyForFactory());
        model.fromCursor(anotherCursor);
        return model;
    }

    public boolean updateItem(Long id, ContentValues contentValues) {
        boolean isUpdated = (database.update(getTableName(), contentValues, KEY_ID + "=?",
                new String[]{id.toString()})) > 0;
        return isUpdated;
    }

    //Прочие служебные методывфзеук
    public void onDestroy() {
        dbOpenHelper.close();
    }

    //Вызывает обновление вида
    protected void refresh() {
        cursor = getAllEntries();
        notifyDataSetChanged();
    }

    // Инициализация адаптера: открываем базу и создаем курсор
    protected final void init() {
        dbOpenHelper = new DbOpenHelper(context, DB_NAME, null, this);
        try {
            database = dbOpenHelper.getWritableDatabase();
        } catch (SQLException e) {
            Log.e(this.toString(), e.getLocalizedMessage());
            throw new Error("The end");
        }
        cursor = getAllEntries();
    }

    protected static class DbOpenHelper extends SQLiteOpenHelper {

        protected AbstractSqlAdapter sqlAdapter;

        public DbOpenHelper(Context context, String name, CursorFactory factory, AbstractSqlAdapter sqlAdapter) {
            super(context, name, factory, sqlAdapter.getDbVersion());
            this.sqlAdapter = sqlAdapter;
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL(sqlAdapter.getCreateTableSql());
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            db.execSQL("DROP TABLE IF EXISTS " + sqlAdapter.getTableName());
            onCreate(db);
        }
    }
}
